#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define MAX_RETRY_COUNT 10

int client_init(const char* server_addr, unsigned short int host) {

    int socketfd = -1; 
    struct sockaddr_in serveraddr; 
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd == -1) {
        perror("Socket creation failed");
        return -1;
    }

    // Get current flags
    int flags = fcntl(socketfd, F_GETFL, 0);
    if (flags == -1) {
        perror("Failed to get socket flags");
        close(socketfd);
        return -1;
    }

    // Set non-blocking mode
    if (fcntl(socketfd, F_SETFL, flags | O_NONBLOCK) < 0) {
        perror("Failed to set non-blocking");
        close(socketfd);
        return -1;
    }

    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(host);

    if (inet_pton(AF_INET, server_addr, &serveraddr.sin_addr) <= 0) {
        printf("inet_pton error for %s \n", server_addr);
        close(socketfd);
        return -1;
    }

    int connect_status = connect(socketfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    if (connect_status < 0 && errno != EINPROGRESS) {
        perror("Immediate connect error");
        close(socketfd);
        return -1;
    }
        // 这个表明建立连接了 但是还没有握手完毕需要等待
    if (connect_status < 0 && errno == EINPROGRESS) {
        printf("Connection in progress...\n");
        //fd_set是一个位图
        fd_set writefds;
        //先全部清0
        FD_ZERO(&writefds);
        //把这个位置为1 write表明的是当write事件发生时select返回
        FD_SET(socketfd, &writefds);

        struct timeval timeout;
        timeout.tv_sec = 5;  // Timeout in seconds
        timeout.tv_usec = 0;

        //如果非阻塞connect建立成功了，客户端的sock_fd就会变成可写的 -- 所以在这里整了一个writefd
        // 实际在这里可以检查多个的
        //! 注意select本身是阻塞的--等待timeout时间
        int select_result = select(socketfd + 1, NULL, &writefds, NULL, &timeout);
        if (select_result < 0) {
            perror("Select error");
            close(socketfd);
            return -1;
        } else if (select_result == 0) {
            printf("Connection timeout\n");
            close(socketfd);
            return -1;
        }
        // 因为就监视了一个所以不用关心
        // 否则就得和FD_ISSET 想要的fd和 writefd了
        // 返回值大于0说明建立联系成功了


        //当非阻塞connect建立成功之后还可以利用getsockopt来读取错误码
        //并自动清除该socket上的错误
        //optval = 0 就是OK 不是0就不OK
        int optval;
        socklen_t optlen = sizeof(optval);
        //读取失败
        if (getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) {
            perror("Getsockopt error");
            close(socketfd);
            return -1;
        }
        //不为0就是有错误
        if (optval != 0) {
            fprintf(stderr, "Connect failed: %s\n", strerror(optval));
            close(socketfd);
            return -1;
        }

        printf("Connection established\n");
 
    } else {        /* 此处表明建立连接失败了因为返回值不是连接上了*/
        printf("Immediate connection established\n");
        return -1;
    }

    printf("=========client init ready, send msg to server.....=====\n");
    return socketfd;
}
